#include "stdafx.h"

#include <vector>
#include "win_frame.h"
#include "h2log.h"


void win_region::remove(RECT& rc)
{
    int i = 0;
    while(i < _blocks.length())
    {
        if(overlap_rect(rc, _blocks[i]))
        {
            RECT tmp = _blocks[i];
            //_blocks.erase(_blocks.begin() + i);
            _blocks.remove(i);
            add_notch_rect(tmp, rc);
            i = 0;
            continue;
        }

        ++i;
    }
}

bool win_region::cover_rect(RECT& rc, RECT& rcRef)
{
    if(rcRef.left < rc.left || rcRef.right > rc.right ||
        rcRef.top < rc.top || rcRef.bottom > rc.bottom)
    {
        return false;
    }
    return true;
}

bool win_region::overlap_rect(RECT& rc, RECT& rcRef)
{
    if(rc.left >= rcRef.right || rc.right <= rcRef.left || 
        rc.top >= rcRef.bottom || rc.bottom <= rcRef.top)
    {
        return false;
    }
    return true;
}

bool win_region::merge_rect(RECT* rc, RECT& rcRef)
{
    bool merged = false;
    if(rc->left >= rcRef.left && rc->right <= rcRef.right && rc->top >= rcRef.top && rc->top <= rcRef.bottom && rc->top != rcRef.top)
    {
        rc->top = rcRef.top;
        merged = true;
    }

    if(rc->left >= rcRef.left && rc->right <= rcRef.right && rc->bottom >= rcRef.top && rc->bottom <= rcRef.bottom && rc->bottom != rcRef.bottom)
    {
        rc->bottom = rcRef.bottom;
        merged = true;
    }

    if(rc->top >= rcRef.top && rc->bottom <= rcRef.bottom && rc->left >= rcRef.left && rc->left <= rcRef.right && rc->left != rcRef.left)
    {
        rc->left = rcRef.left;
        merged = true;
    }

    if(rc->top >= rcRef.top && rc->bottom <= rcRef.bottom && rc->right >= rcRef.left && rc->right <= rcRef.right && rc->right != rcRef.right)
    {
        rc->right = rcRef.right;
        merged = true;
    }

    return merged;
}

void win_region::add_rect(RECT& rc)
{
    int i = 0;
    while(i < _blocks.length())
    {
        // to be added rect could be covered by existing rect
        if(cover_rect(_blocks[i], rc))
        {
            return;
        }

        // to be added rect covers existing rect
        if(cover_rect(rc, _blocks[i]))
        {
            //_blocks.erase(_blocks.begin() + i);
            _blocks.remove(i);
            continue;
        }

        ++i;
    }


    for(i = 0; i < _blocks.length(); ++i)
    {
        merge_rect(&rc, _blocks[i]);
    }

    _blocks.push_back(rc);
}

void win_region::add_notch_rect(RECT& rcSrc, RECT& rcRemoved)
{
    if(rcRemoved.left > rcSrc.left)
    {
        RECT tmp = { rcSrc.left, rcSrc.top, min(rcSrc.right, rcRemoved.left), rcSrc.bottom};
        add_rect(tmp);
    }
    if(rcRemoved.top > rcSrc.top)
    {
        RECT tmp = { rcSrc.left, rcSrc.top, rcSrc.right, min(rcSrc.bottom, rcRemoved.top)};
        add_rect(tmp);
    }
    if(rcRemoved.right < rcSrc.right)
    {
        RECT tmp = { max(rcRemoved.right, rcSrc.left), rcSrc.top, rcSrc.right, rcSrc.bottom};
        add_rect(tmp);
    }
    if(rcRemoved.bottom < rcSrc.bottom)
    {
        RECT tmp = { rcSrc.left, max(rcRemoved.bottom, rcSrc.top), rcSrc.right, rcSrc.bottom};
        add_rect(tmp);
    }
}

void win_region::debug_info()
{

    LOG::output(L"region blocks:\n");

    for(int i = 0; i < _blocks.length(); ++i)
    {
        STRING::ansi tmp(256);
        sprintf_s(*tmp, 256, "%02d: %dx%d - %dx%d\n", i, _blocks[i].left, _blocks[i].top, _blocks[i].right, _blocks[i].bottom);
        LOG::output(*STRING::unicode(tmp));
    }

}


bool win_region::find_align_rect(int align, RECT* rc)
{
    if(_blocks.length() <= 0)
    {
        return false;
    }

    int index = 0;
    for(int i = 1; i < _blocks.length(); ++i)
    {
        switch(align)
        {
        case ALIGN_TOP:
            if(_blocks[i].top > _blocks[index].top) continue;
            if(_blocks[i].top < _blocks[index].top) { index = i; continue; }
            break;
        case ALIGN_BOTTOM:
            if(_blocks[i].bottom < _blocks[index].bottom) continue;
            if(_blocks[i].bottom > _blocks[index].bottom) { index = i; continue; }
            break;
        case ALIGN_LEFT:
            if(_blocks[i].left > _blocks[index].left) continue;
            if(_blocks[i].left < _blocks[index].left) { index = i; continue; }
            break;
        case ALIGN_RIGHT:
            if(_blocks[i].right < _blocks[index].right) continue;
            if(_blocks[i].right > _blocks[index].right) { index = i; continue; }
            break;
        }

        // the max area block will be adopted
        if((_blocks[i].right - _blocks[i].left) * (_blocks[i].bottom - _blocks[i].top) >
            (_blocks[index].right - _blocks[index].left) * (_blocks[index].bottom - _blocks[index].top))
        {
            index = i;
        }
    }

    if(rc)
    {
        *rc = _blocks[index];
    }

    return true;
}


bool win_layout::accommodate(win_tile* t)
{
    RECT rc;
    if(!t || !_region.find_align_rect(t->align, &rc))
    {
        return false;
    }

    int width = min(t->max_width, rc.right - rc.left);
    int height = min(t->max_height, rc.bottom - rc.top);

    if(width != (rc.right - rc.left) || height != (rc.bottom - rc.top))
    switch(t->corner)
    {
    default:
    case CORNER_TOP_LEFT:
        rc.right = rc.left + width;
        rc.bottom = rc.top + height;
        break;
    case CORNER_TOP_RIGHT:
        rc.left = rc.right - width;
        rc.bottom = rc.top + height;
        break;
    case CORNER_BOTTOM_LEFT:
        rc.right = rc.left + width;
        rc.top = rc.bottom - height;
        break;
    case CORNER_BOTTOM_RIGHT:
        rc.left = rc.right - width;
        rc.top = rc.bottom - height;
        break;
    }

    t->show_window(true);
    t->move_window(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
    _region.remove(rc);

    return true;
}



void win_layout::resize(int width, int height)
{
    RECT rc = {0, 0, width, height}; 

    _region.reset(rc); 
 
    for(int i = 0; i < _tiles.length(); ++i) 
    {
        if(!accommodate(_tiles[i]))
        {
            _tiles[i]->show_window(false);
        }
    }
}

void win_layout::add_tile(win_tile *t)
{
    if(!t)
    {
        return;
    }

    for(int i = 0 ; i < _tiles.length(); ++i)
    {
        if(t->priority > _tiles[i]->priority)
        {
            _tiles.insert(i, t);
            return;
        }
    }

    _tiles.push_back(t);
}




win_frame::win_frame()
{
    memset(&_drag, 0, sizeof(_drag));
    wcscpy_s(_szClassName, L"WinFrame");
}

win_frame::~win_frame()
{
}



LRESULT win_frame::OnSize(DWORD dwFlags, WORD width, WORD height)
{
    resize(width, height);
    return 0;
}
